package com.yincb.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class DynamicCompilationService {
    
    private static final Logger logger = LoggerFactory.getLogger(DynamicCompilationService.class);
    
    private final Map<String, Class<?>> compiledClasses = new ConcurrentHashMap<>();
    private final Path tempDir;
    
    public DynamicCompilationService() throws IOException {
        // 创建临时目录用于存储编译后的类文件
        this.tempDir = Files.createTempDirectory("dynamic-classes");
        this.tempDir.toFile().deleteOnExit();
    }
    
    /**
     * 编译Java源代码字符串
     * @param className 类名（包含包名）
     * @param sourceCode Java源代码
     * @return 编译后的Class对象
     * @throws Exception 编译失败时抛出异常
     */
    public Class<?> compileClass(String className, String sourceCode) throws Exception {
        logger.info("开始编译类: {}", className);
        
        try {
            // 创建源文件
            Path sourceFile = createSourceFile(className, sourceCode);
            
            // 使用系统编译器编译
            compileWithSystemCompiler(sourceFile);
            
            // 加载编译后的类
            Class<?> clazz = loadCompiledClass(className);
            compiledClasses.put(className, clazz);
            
            logger.info("类编译成功: {}", className);
            return clazz;
            
        } catch (Exception e) {
            logger.error("编译类失败: {}", className, e);
            throw new RuntimeException("编译失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 使用系统编译器编译Java文件
     */
    private void compileWithSystemCompiler(Path sourceFile) throws Exception {
        // 获取Java编译命令
        String javaHome = System.getProperty("java.home");
        String javacPath;
        
        if (javaHome.endsWith("jre")) {
            javacPath = javaHome.substring(0, javaHome.length() - 3) + "bin" + File.separator + "javac";
        } else {
            javacPath = javaHome + File.separator + "bin" + File.separator + "javac";
        }
        
        // Windows系统添加.exe扩展名
        if (System.getProperty("os.name").toLowerCase().contains("windows")) {
            javacPath += ".exe";
        }
        
        File javacFile = new File(javacPath);
        if (!javacFile.exists()) {
            // 尝试使用系统PATH中的javac
            javacPath = "javac";
        }
        
        // 构建编译命令
        List<String> command = new ArrayList<>();
        command.add(javacPath);
        command.add("-d");
        command.add(tempDir.toString());
        command.add("-cp");
        command.add(getClassPath());
        command.add(sourceFile.toString());
        
        logger.debug("执行编译命令: {}", String.join(" ", command));
        
        // 执行编译
        ProcessBuilder pb = new ProcessBuilder(command);
        pb.redirectErrorStream(true);
        Process process = pb.start();
        
        // 读取输出
        java.io.InputStream inputStream = process.getInputStream();
        java.io.ByteArrayOutputStream result = new java.io.ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inputStream.read(buffer)) != -1) {
            result.write(buffer, 0, length);
        }
        String output = result.toString("UTF-8");
        int exitCode = process.waitFor();
        
        if (exitCode != 0) {
            throw new RuntimeException("编译失败，退出码: " + exitCode + "\n输出: " + output);
        }
        
        logger.debug("编译输出: {}", output);
    }
    
    /**
     * 创建源文件
     */
    private Path createSourceFile(String className, String sourceCode) throws IOException {
        // 解析包名和类名
        String packageName = "";
        String simpleClassName = className;
        
        int lastDotIndex = className.lastIndexOf('.');
        if (lastDotIndex != -1) {
            packageName = className.substring(0, lastDotIndex);
            simpleClassName = className.substring(lastDotIndex + 1);
        }
        
        // 创建包目录
        Path packageDir = tempDir.resolve(packageName.replace('.', File.separatorChar));
        Files.createDirectories(packageDir);
        
        // 创建源文件
        Path sourceFile = packageDir.resolve(simpleClassName + ".java");
        Files.write(sourceFile, sourceCode.getBytes());
        
        return sourceFile;
    }
    
    /**
     * 获取类路径
     */
    private String getClassPath() {
        StringBuilder classPath = new StringBuilder();
        
        // 添加当前类路径
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        if (classLoader instanceof URLClassLoader) {
            URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
            for (URL url : urlClassLoader.getURLs()) {
                if (classPath.length() > 0) {
                    classPath.append(File.pathSeparator);
                }
                classPath.append(url.getPath());
            }
        }
        
        // 添加系统属性中的类路径
        String systemClassPath = System.getProperty("java.class.path");
        if (systemClassPath != null && !systemClassPath.isEmpty()) {
            if (classPath.length() > 0) {
                classPath.append(File.pathSeparator);
            }
            classPath.append(systemClassPath);
        }
        
        return classPath.toString();
    }
    
    /**
     * 加载编译后的类
     */
    private Class<?> loadCompiledClass(String className) throws Exception {
        // 创建自定义类加载器
        DynamicClassLoader classLoader = new DynamicClassLoader(tempDir.toFile());
        Class<?> clazz = classLoader.loadClass(className);
        
        // 验证包信息，如果为null则记录警告
        if (clazz.getPackage() == null) {
            logger.warn("动态加载的类 {} 没有包信息，这可能是由于类加载器或编译配置问题", className);
        }
        
        return clazz;
    }
    
    /**
     * 获取已编译的类
     */
    public Class<?> getCompiledClass(String className) {
        return compiledClasses.get(className);
    }
    
    /**
     * 清理资源
     */
    public void cleanup() {
        try {
            deleteDirectory(tempDir.toFile());
            compiledClasses.clear();
        } catch (IOException e) {
            logger.warn("清理临时文件失败", e);
        }
    }
    
    /**
     * 递归删除目录
     */
    private void deleteDirectory(File directory) throws IOException {
        if (directory.exists()) {
            File[] files = directory.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.isDirectory()) {
                        deleteDirectory(file);
                    } else {
                        file.delete();
                    }
                }
            }
            directory.delete();
        }
    }
    
    /**
     * 自定义类加载器
     */
    private static class DynamicClassLoader extends ClassLoader {
        private final File classDirectory;
        
        public DynamicClassLoader(File classDirectory) {
            this.classDirectory = classDirectory;
        }
        
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            try {
                String classFileName = name.replace('.', File.separatorChar) + ".class";
                File classFile = new File(classDirectory, classFileName);
                
                if (!classFile.exists()) {
                    throw new ClassNotFoundException("类文件不存在: " + name);
                }
                
                byte[] classBytes = Files.readAllBytes(classFile.toPath());
                return defineClass(name, classBytes, 0, classBytes.length);
            } catch (IOException e) {
                throw new ClassNotFoundException("加载类失败: " + name, e);
            }
        }
    }
}